import { Body, Controller, Delete, Get, HttpException, HttpStatus, Param, Post, Put, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ApiBearerAuth, ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger';
import { Authorities } from 'src/decorators/authorities.decorator';
import { AuthoritiesGuard } from 'src/guards/authorities.guard';
import { Guard } from 'src/modules/guard/constants/guard.constant';
import { RequestContext } from '../../../../context/request.context';
import { LantUtil } from '../../../../utils/lant.util';
import { BoolResDto } from '../../../common/dtos/bool.res.dto';
import { IdReqDto } from '../../../common/dtos/id.req.dto';
import { IdResDto } from '../../../common/dtos/id.res.dto';
import { LogAppender } from '../../../log/constants/log.constant';
import { LogService } from '../../../log/services/log.service';
import { CreateOrganizationAdminReqDto } from '../../dtos/organization/admin/create-organization.admin.req.dto';
import { CreateTempOrganizationAdminReqDto } from '../../dtos/organization/admin/create.temp.organization.admin.req.dto';
import { GetOrganizationTreeListAdminResDto } from '../../dtos/organization/admin/get-organization-tree-list.admin.res.dto';
import { UpdateOrganizationTreeListAdminReqDto } from '../../dtos/organization/admin/update-organization-tree-list.admin.req.dto';
import { UpdateOrganizationAdminReqDto } from '../../dtos/organization/admin/update-organization.admin.req.dto';
import { OrganizationService } from '../../services/organization.service';
import { v4 as uuid } from 'uuid';
import { IdNameResDto } from '../../../common/dtos/id-name.res.dto';

@ApiBearerAuth()
@ApiTags('organizations')
@Controller('admin/organizations')
export class OrganizationAdminController {
  constructor(private readonly organizationService: OrganizationService, private readonly logService: LogService, private readonly lantUtil: LantUtil) {}

  @ApiOperation({ summary: '创建组织' })
  @ApiOkResponse({ description: '返回组织编号', type: IdResDto })
  @Authorities(Guard.OrganizationManage)
  @UseGuards(AuthGuard(), AuthoritiesGuard)
  @Post()
  async create(@Body() body: CreateOrganizationAdminReqDto): Promise<IdResDto> {
    try {
      const parent = await this.organizationService.findOneById(body.parent_id);
      if (!parent) throw new HttpException('上级组织不存在或已被删除', HttpStatus.BAD_REQUEST);

      const organizationList = await this.organizationService.findDescendantsByName(body.name, parent);
      if (organizationList && organizationList.length > 0) throw new HttpException('组织已存在，不能重复创建', HttpStatus.BAD_REQUEST);

      const newOrganization = await this.organizationService.create(body.name, parent.level + 1, body.description, parent);

      return { id: newOrganization.id };
    } catch (error) {
      if (error instanceof HttpException) throw error;
      this.logService.error(LogAppender.organization, `Cannot create organization by ${JSON.stringify(body)}, the error is ${error}`, this.lantUtil.parseError(error));
      throw new HttpException(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  @ApiOperation({ summary: '创建临时组织' })
  @ApiOkResponse({ description: '返回临时组织编号', type: IdResDto })
  @Authorities(Guard.OrganizationManage)
  @UseGuards(AuthGuard(), AuthoritiesGuard)
  @Post('temp')
  async createTemp(@Body() body: CreateTempOrganizationAdminReqDto): Promise<IdResDto> {
    try {
      const parent = await this.organizationService.findOneById(body.parent_id);
      if (!parent) throw new HttpException('上级组织不存在或已被删除', HttpStatus.BAD_REQUEST);

      const tempName = 'temp_' + uuid();
      const tempOrganization = await this.organizationService.create(tempName, parent.level + 1, undefined, parent);

      return { id: tempOrganization.id };
    } catch (error) {
      if (error instanceof HttpException) throw error;
      this.logService.error(LogAppender.organization, `Cannot create temp organization by ${JSON.stringify(body)}, the error is ${error}`, this.lantUtil.parseError(error));
      throw new HttpException(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  @ApiOperation({ summary: '删除组织' })
  @ApiOkResponse({ description: '返回删除结果', type: BoolResDto })
  @Authorities(Guard.OrganizationManage)
  @UseGuards(AuthGuard(), AuthoritiesGuard)
  @Delete(':id')
  async delete(@Param() { id }: IdReqDto): Promise<BoolResDto> {
    try {
      const organization = await this.organizationService.findOneById(id);
      if (!organization) throw new HttpException('组织不存在或已被删除', HttpStatus.BAD_REQUEST);

      const childrenCount = await this.organizationService.findCount(organization);
      if (childrenCount > 1) throw new HttpException('该组织下存在节点，不能删除', HttpStatus.BAD_REQUEST);

      const updateResult = await this.organizationService.deleteOneById(id);

      return { result: !!updateResult.affected };
    } catch (error) {
      if (error instanceof HttpException) throw error;
      this.logService.error(LogAppender.organization, `Cannot delete organization by ${id}, the error is ${error}`, this.lantUtil.parseError(error));
      throw new HttpException(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  /**
   * 递归更新组织信息
   * @param organizationDto 组织对象
   */
  async updateOrganization(organizationDto: UpdateOrganizationTreeListAdminReqDto) {
    await this.organizationService.update(organizationDto.id, organizationDto.name, organizationDto.description);
    if (organizationDto.children && organizationDto.children.length > 0) {
      for (const organization of organizationDto.children) {
        await this.updateOrganization(organization);
      }
    }
  }

  @ApiOperation({ summary: '批量更新组织' })
  @ApiOkResponse({ description: '返回组织批量更新结果', type: BoolResDto })
  @Authorities(Guard.OrganizationManage)
  @UseGuards(AuthGuard(), AuthoritiesGuard)
  @Put()
  async updateAll(@Body() body: UpdateOrganizationTreeListAdminReqDto): Promise<BoolResDto> {
    try {
      await this.updateOrganization(body);

      return { result: true };
    } catch (error) {
      if (error instanceof HttpException) throw error;
      this.logService.error(LogAppender.organization, `Cannot update organization tree, the error is ${error}`, this.lantUtil.parseError(error));
      throw new HttpException(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  @ApiOperation({ summary: '更新组织' })
  @ApiOkResponse({ description: '返回更新结果', type: BoolResDto })
  @Authorities(Guard.OrganizationManage)
  @UseGuards(AuthGuard(), AuthoritiesGuard)
  @Put(':id')
  async update(@Param() { id }: IdReqDto, @Body() body: UpdateOrganizationAdminReqDto): Promise<BoolResDto> {
    try {
      const organization = await this.organizationService.findOneById(id);
      if (!organization) throw new HttpException('组织不存在或已被删除', HttpStatus.BAD_REQUEST);

      const organizationList = await this.organizationService.findDescendantsByName(body.name, organization.parent);
      if (organizationList && organizationList.length > 0) {
        const sameOrganization = organizationList.find(organization => organization.id == id && organization.name == body.name);
        if (!sameOrganization) throw new HttpException('组织名称不能重复', HttpStatus.BAD_REQUEST);
      }

      await this.organizationService.update(id, body.name, body.description);

      return { result: true };
    } catch (error) {
      if (error instanceof HttpException) throw error;
      this.logService.error(LogAppender.organization, `Cannot update organization by ${JSON.stringify(body)}, the error is ${error}`, this.lantUtil.parseError(error));
      throw new HttpException(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  @ApiOperation({ summary: '查询子组织列表' })
  @ApiOkResponse({ description: '返回符合条件的子组织列表', type: IdNameResDto, isArray: true })
  @Get('children')
  async getChildren(): Promise<IdNameResDto[]> {
    try {
      const root = await this.organizationService.findOneRoot();
      const organizationList = await this.organizationService.findChildren(root);
      return organizationList?.map(organization => {
        return {
          name: organization.name,
          id: organization.id
        };
      });
    } catch (error) {
      if (error instanceof HttpException) throw error;
      this.logService.error(LogAppender.organization, `Cannot get organization list, the error is ${error}`, this.lantUtil.parseError(error));
      throw new HttpException(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  @ApiOperation({ summary: '返回组织所有直接子类别（及其嵌套类别）' })
  @ApiOkResponse({ description: '返回组织所有直接子类别（及其嵌套类别）', type: GetOrganizationTreeListAdminResDto })
  @Authorities(Guard.OrganizationManage, Guard.OrganizationView)
  @UseGuards(AuthGuard(), AuthoritiesGuard)
  @Get()
  async getAll(): Promise<GetOrganizationTreeListAdminResDto> {
    try {
      await this.organizationService.deleteAllByName('temp_');

      const currentUser = RequestContext.currentUser();
      const parent = await this.organizationService.findOneById(currentUser.jobId);
      const organizationTree = await this.organizationService.findDescendantsTree(parent);

      return {
        id: organizationTree.id,
        name: organizationTree.name,
        level: organizationTree.level,
        description: organizationTree.description,
        children: organizationTree.children
      };
    } catch (error) {
      if (error instanceof HttpException) throw error;
      this.logService.error(LogAppender.organization, `Cannot get organization tree, the error is ${error}`, this.lantUtil.parseError(error));
      throw new HttpException(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }
}
